﻿using System;
using System.IO;
using System.Reflection;
using ArtSpec;

namespace Spec
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
            Console.WriteLine(
@"
ArtSpec validation tool.
Thanks for using ArtSpec. You can show your appreciation and support future development by donating.
http://code.google.com/p/artspec/
");

            if (args.Length != 1)
            {
                Console.WriteLine("Usage: spec.exe assembly");
                Environment.ExitCode = 1;
                return;
            }

            var assemblyPath = args[0];
            var assemblyFile = new FileInfo(assemblyPath);
            if (assemblyFile.Exists)
            {
                Console.WriteLine("Validation started");
                ProcessAssembly(assemblyFile.FullName);
                Console.WriteLine("Validation completed");
            }
            else
            {
                Console.WriteLine("Can't find assembly");
                Environment.ExitCode = 1;
            }
        }

        private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Console.WriteLine("Fatal error: {0}", e.ExceptionObject);
        }

        private static void ProcessAssembly(string path)
        {
            var assembly = Assembly.LoadFile(path);
            var found = false;
            foreach(var type in assembly.GetTypes())
            {
                if (!IsSpec(type)) continue;
                found = true;
                ProcessSpec(type);
            }
            if (found) return;
            Console.WriteLine("Assembly doesn't contain specification");
            Environment.ExitCode = 1;
        }

        private static void ProcessSpec(Type type)
        {
            var spec = (ArtSpec.Spec) Activator.CreateInstance(type);
            spec.OnResult +=
                delegate(ISpec sender)
                    {
                        var error = sender.Error;
                        Console.ForegroundColor = error == null ? ConsoleColor.Green : ConsoleColor.DarkRed;
                        Console.Write(sender.Description);
                        if (error != null)
                        {
                            Environment.ExitCode = 1;
                            Console.WriteLine(": {0}", error);
                        }
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.White;
                    };

            spec.Validate();
        }

        private static bool IsSpec(Type type)
        {
            return type.IsSubclassOf(typeof (ArtSpec.Spec));
        }
    }
}
